package savet.util;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 *
 * @author Adisson
 */
public final class DataUtil {

    /**
     * HH:mm
     */
    public static final String FORMATO_HORA = "HH:mm";

    /**
     * MM/yyyy
     */
    public static final String FORMATO_MES_ANO = "MM/yyyy";
    /**
     * dd/MM/yyyy
     */
    public static final String FORMATO_PADRAO = "dd/MM/yyyy";
    /**
     * dd/MM/yyyy HH:mm
     */
    public static final String FORMATO_DATETIME = "dd/MM/yyyy HH:mm";
    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static final String FORMATO_TIMESTAMP_BD = "yyyy-MM-dd HH:mm:ss";

    private DataUtil() {
    }

    /**
     * Converte {@link Date} para o formato compativel com SGBDR {@link Timestamp}.
     *
     * @param date
     * @return data formatada para Timestamp
     */
    public static Date criaTimestamp(Date date) {

        // Configura a formatacao da data
        String dateFormatted = converteDateToString(date, FORMATO_TIMESTAMP_BD);

        // Cria novo Date formatado para o banco de dados
        Timestamp timeStamp = Timestamp.valueOf(dateFormatted);
        timeStamp.setNanos(0);

        return timeStamp;

    }

    /**
     * Converte String em {@link Date} no formato dd/MM/yyyy
     *
     * @param data
     * @return date
     * @throws ParseException
     */
    public static Date criarDate(String data) throws ParseException {
        Date date = new Date();

        date = convert("dd/MM/yyyy", data);

        return date;
    }

    /**
     * Converte String em {@link Date} no formato dd/MM/yyyy HH:mm
     *
     * @param   data
     * @return  date
     * @throws  ParseException
     */
    public static Date criarDateTime(String data) throws ParseException {
        Date date = new Date();

        date = convert(FORMATO_DATETIME, data);

        // Converte para formato Timestamp
        date = criaTimestamp(date);
        return date;
    }

    /**
     * Converte String em {@link Date} no formato HH:mm
     *
     * @param data
     * @return date
     * @throws ParseException
     */
    public static Date criarHora(String hora) throws ParseException {
        Date date = convert(FORMATO_HORA, hora);
        return date;
    }

    public static Date mesclarDataHora(Date data, String hora) throws ParseException {

        String dataFormatada = converteDateToString(data, FORMATO_PADRAO);
        return mesclarDataHora(dataFormatada, hora);

    }

    public static Date mesclarDataHora(String data, String hora) throws ParseException {

        return criaTimestamp(convert(FORMATO_DATETIME, data + " " + hora));

    }

    /**
     * Converte um objeto {@link Date} num formato definido no parametro.
     *
     * @param date
     * @param formato desejado para conversao
     * @return String de data formatada
     * @see DataUtil
     */
    public static String converteDateToString(Date date, String formato) {
        SimpleDateFormat formatter = new SimpleDateFormat(formato);
        String dateFormatted = formatter.format(date);
        return dateFormatted;
    }

    public static int extrairDiaSemana(Date date) {
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return calendar.get(GregorianCalendar.DAY_OF_WEEK);
    }

    /**
     * Converte String em {@link Date} no formato que for passado como parametro
     *
     * @param data
     * @return date
     * @throws ParseException
     */
    private static Date convert(String formato, String valor) throws ParseException {
        Date date = new Date();
        // Converte String no formato passado no parametro para objeto Date
        SimpleDateFormat formatter = new SimpleDateFormat(formato);
        date = formatter.parse(valor);

        return date;
    }

    /**
     * Formata objeto Date no padrao timestamp do banco de dados.<br/>
     *
     * <code>yyyy-MM-dd HH:mm:ss</code>
     *
     * @param data
     * @return objeto {@link Date} formatado
     */
    public static Date getDataFormatada(Date data) {
        Timestamp dataFormatada = null;

        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dataFormatada = Timestamp.valueOf(format.format(data));
        dataFormatada.setNanos(0);

        return dataFormatada;
    }

    /**
     * Efetua a subtracao de duas datas para verificar qual a diferenca em dias entre essas datas.
     * 
     * @param dataMaior
     * @param dataMenor
     * @return diferenca em dias de duas datas
     */
    public static long getDiferencaDatas(Date dataMaior, Date dataMenor) {

        long dMaior = dataMaior.getTime();
        long dMenor = dataMenor.getTime();

        // Quantidade de milissegundos em um dia
        int tempoDia = 1000 * 60 * 60 * 24;

        long result = (dMaior - dMenor) / tempoDia;

        return result;
    }

    /**
     * Formata objeto Date no padrao timestamp do banco de dados a partir de uma String.<br/>
     *
     * <code>
     *  String no formato dd/MM/yyyy HH:mm para Timestamp yyyy-MM-dd HH:mm:ss
     * </code>
     *
     * @param data no formato dd/MM/yyyy HH:mm
     * @return objeto {@link Date} formatado
     */
    public static Date valueOf(String data) {
        try {
            // Transforma String em java.util.Date
            SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
            Date parse = format.parse(data);

            // Cria Timestamp que possui o formato do BD
            Timestamp dateFromString = new Timestamp(parse.getTime());
            dateFromString.setNanos(0);

            System.out.println(data + " convertido para " + dateFromString);
            return dateFromString;
        } catch (ParseException ex) {
            System.err.println(ex.getMessage());
            return null;
        }
    }

    /**
     * Verifica se a data este entre um determinado periodo.
     * 
     * @param dataInicio referente ao inicio do periodo
     * @param dataFim referente ao fim do periodo
     * @param data sera verificada
     * @return true se a data estiver no intervalo do periodo passado
     */
    public static boolean isBetween(Date dataInicio, Date dataFim, Date data) {
        Calendar di = new GregorianCalendar();
        Calendar df = new GregorianCalendar();
        Calendar d = new GregorianCalendar();

        di.setTime(dataInicio);
        df.setTime(dataFim);
        d.setTime(data);

        return d.after(di) && d.before(df);
    }

    /**
     * Compara duas datas e verificam se sao iguais de acordo com o padrao {@link #FORMATO_PADRAO}.
     * <br/>
     *
     * @param d1 primeira data para comparacao
     * @param d2 segunda data para comparacao
     * @return true caso as datas sejam iguais
     */
    public static boolean equals (Date d1, Date d2) {
        return equals(d1, d2, FORMATO_PADRAO);
    }

    /**
     * Compara duas datas e verificam se sao iguais de acordo com o padrao de
     * formatacao de datas passado como parametro.<br/>
     * Ex:
     * <code>
     * equals(data1, data2, {@link #FORMATO_PADRAO}.
     * </code>
     *
     * @param d1 primeira data para comparacao
     * @param d2 segunda data para comparacao
     * @param formato padrao para compara&ccedil;&atilde;o das datas
     *
     * @return true caso as datas sejam iguais
     */
    public static boolean equals (Date d1, Date d2, String formato) {
        if (d1 == null && d2 == null) {
            return true;
        }
        if (d1 == null || d2 == null) {
            return false;
        }
        
        String data1 = converteDateToString(d1, formato);
        String data2 = converteDateToString(d2, formato);

        return data1.equals(data2);
    }
}
